﻿using System;
using System.Xml;

namespace IniFileManager
{
	/// <summary>
	/// Class representing inner structure of an unsigned element
	/// within property defined by library user in ini schema.
	/// </summary>
	internal sealed class IniUnsignedElementSchema : IniElementSchema
	{
		private readonly ulong defaultValue;
		private readonly ulong minValue;
		private readonly ulong maxValue;

		/// <summary>
		/// Creates "IniUnsignedElementSchema" from xml node in ini schema xml representation.
		/// </summary>
		/// <param name="unsignedElementNode">Ini unsigned element schema xml node.</param>
		/// <exception cref="System.FormatException">Trown if is provided xml node not valid unsigned element node.</exception>
		internal IniUnsignedElementSchema( XmlNode unsignedElementNode )
		{
			// Embedded "IniSchema.xsd"'s definition guarantees existence and format of this attribute:
			this.defaultValue = ulong.Parse( unsignedElementNode.Attributes[IniSchemaXsd.ATTRIBUTE_DEFAULT].Value );
			if( unsignedElementNode.Attributes[IniSchemaXsd.ATTRIBUTE_MIN] != null )
			{
				this.minValue = Convert.ToUInt64( unsignedElementNode.Attributes[IniSchemaXsd.ATTRIBUTE_MIN].Value );
			}
			else
			{
				this.minValue = ulong.MinValue;
			}
			if( unsignedElementNode.Attributes[IniSchemaXsd.ATTRIBUTE_MAX] != null )
			{
				this.maxValue = Convert.ToUInt64( unsignedElementNode.Attributes[IniSchemaXsd.ATTRIBUTE_MAX].Value );
			}
			else
			{
				this.maxValue = ulong.MaxValue;
			}

			// If condition minValue <= defaultValue <= maxValue isn't satisfied, 
			// throw an exception. (Rewritten using deMorgan rules):
			if( defaultValue < minValue || defaultValue > maxValue )
			{
				throw new ArgumentException();
			}
		}

		/// <summary>
		/// Boxed default unsigned value of an element into object.
		/// </summary>
		internal override object DefaulValue
		{
			get
			{
				return this.defaultValue;
			}
		}

		/// <summary>
		/// Tells wheather a value is valid within.
		/// </summary>
		/// <param name="boxedValue">Value boxed in object.</param>
		/// <returns>True if value valid within. False if not.</returns>
		internal override bool IsValueValidWithin( object boxedValue )
		{
			ulong value;
			try
			{
				value = (ulong)boxedValue;
			}
			catch
			{
				return false;
			}

			// If condition minValue <= defaultValue <= maxValue isn't satisfied, 
			// value is not valid within.
			if( value >= this.minValue && value <= this.maxValue )
			{
				return true;
			}
			else
			{
				return false;
			}
		}

	}
}
